﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using System.Drawing;

namespace Laboratorium1
{
    class MyObject
    {
        private Mesh m;                 //Mesh - klasa siatki obiektu
        private Device dev;             
        private ExtendedMaterial[] ExtendedMaterials;   // Tablica ExtendedMateriałów obiektu, z której wydobędziemy
        private Texture[] Textures;                     // tekstury
        private Material[] Materials;                   // i materiały
        public Vector3 center, BoxMin, BoxMax;          // center, radius - sfera otaczająca
        public float radius;                            // BoxMin,BoxMax - box otaczający

        public MyObject(ref Device d)             // prosty konstruktor
        {
            m=null;
            dev = d;
        }

        public void Render()                // Rendering obiektu na device
        {
            dev.VertexFormat = m.VertexFormat;   //Ustalamy Format Vertexów
            // Draw the wireframe cube
            int numSubSets = m.GetAttributeTable().Length;
            for (int i = 0; i < numSubSets; ++i)
            {
                m.DrawSubset(i);
            }
        }

        public Mesh generateSphere()
        {
            Mesh mesh = null;
            short numSegments = 24;
            short numSlices = 24;
            double theta = 0.0, phi = 0.0, r = 5.0;
            double segStep = (2.0 * Math.PI) / numSegments;
            double sliStep = (Math.PI) / numSlices;
            int numVerts = numSegments * (numSlices-1) +2;
            int numFaces = numSegments * (numSlices-1)*2;

            // generating vertices
            CustomVertex.PositionNormalColored[] vertices = new CustomVertex.PositionNormalColored[numVerts];
            for (int i = 0; i < numVerts; ++i)
            {
                vertices[i].X = (float)(r * Math.Sin(phi) * Math.Cos(theta));
                vertices[i].Y = (float)(r * Math.Cos(phi));
                vertices[i].Z = (float)(r * Math.Sin(phi) * Math.Sin(theta));

                vertices[i].Nx = vertices[i].X / (float)r;
                vertices[i].Ny = vertices[i].Y / (float)r;
                vertices[i].Nz = vertices[i].Z / (float)r;

                vertices[i].Color = Color.Green.ToArgb();

                if (i % numSegments == 0)
                {
                    theta = 0.0;
                    phi += sliStep;
                }
                theta += segStep;

            }

            // generating indexes
            short[] indices = new short[numFaces * 3];

            int k = 0;


            //construct index list
            for (short i = 1; i <= numSegments; ++i)
            {
                // TOP POLE
                indices[k + 0] = 0;
                indices[k + 2] = i;
                indices[k + 1] = (short)(i % numSegments + 1);

                k += 3;
            }

            for (int i = 0; i < numSlices - 2; ++i)
            {
                for (int j = 1; j <= numSegments; ++j)
                {
                    // CENTER RING/COLUMN QUADS
                    indices[k + 0] = (short)((i + 1) * numSegments + j);		// bottom left quad vert
                    indices[k + 1] = (short)(i * numSegments + j);			// top left quad vert
                    indices[k + 2] = (short)(i * numSegments + (j % numSegments + 1));		// top right quad vert
                    indices[k + 3] = (short)((i + 1) * numSegments + j);		// bottom left quad vert
                    indices[k + 4] = (short)(i * numSegments + (j % numSegments + 1));			// top left quad vert
                    indices[k + 5] = (short)((i + 1) * numSegments + (j % numSegments + 1));		// top right quad vert
                    k += 6;
                }
            }

            for (short i = 0; i < numSegments; ++i)
            {
                // BOTTOM POLE
                indices[k + 0] = (short)(numVerts - 1);
                indices[k + 1] = (short)(numVerts - numSegments - 1 + i);
                indices[k + 2] = (short)(numVerts - numSegments - 1 + (i + 1) % numSegments);
                k += 3;
            }


            // attributes
            AttributeRange attributeRange = new AttributeRange();
            attributeRange.AttributeId = 0;
            attributeRange.FaceStart = 0;
            attributeRange.FaceCount = numFaces;
            attributeRange.VertexStart = 0;
            attributeRange.VertexCount = vertices.Length;


            mesh = new Mesh(numFaces, vertices.Length, MeshFlags.Managed, CustomVertex.PositionNormalColored.Format, dev);
            mesh.VertexBuffer.SetData(vertices, 0, LockFlags.None);

            mesh.IndexBuffer.SetData(indices, 0, LockFlags.None);
            mesh.SetAttributeTable(new AttributeRange[] { attributeRange });
            return mesh;
        }

        public Mesh generateTorus()
        {
            Mesh mesh = null;
            short numSegments = 15;
            short numSlices = 8;
            double theta = 0.0, phi = 0.0, 
                   r = 2.0, R = 5.0;

            double segStep = (2 * Math.PI) / numSegments;
            double sliStep = (2 * Math.PI) / numSlices;

            int numVerts = numSegments * numSlices;
            int numFaces = numSegments * numSlices * 2;

            // generating vertices
            CustomVertex.PositionNormalColored[] vertices = new CustomVertex.PositionNormalColored[numVerts];
            for (int i = 0; i < numVerts; ++i)
            {

                if (i > 0 && i % numSlices == 0)
                {
                    theta = 0.0;
                    phi += segStep;
                }
                vertices[i].X = (float)(Math.Cos(phi) * (R + r * Math.Cos(theta)));
                vertices[i].Y = (float)(Math.Sin(phi) * (R + r * Math.Cos(theta)));
                vertices[i].Z = (float)(r * Math.Sin(theta));

                vertices[i].Nx = (float)((vertices[i].X - Math.Cos(phi) * R) / r);
                vertices[i].Ny = (float)((vertices[i].Y - Math.Sin(phi) * R) / r);
                vertices[i].Nz = (float)(vertices[i].Z / r);

                System.Console.Out.WriteLine(vertices[i].Position);

                vertices[i].Color = Color.Green.ToArgb();
        

                theta += sliStep;
            }

            // generating indexes
            short[] indices = new short[numFaces * 3];

            int k = 0;


            for (int i = 0; i < numSegments; ++i)
            {
                for (int j = 0; j < numSlices; ++j)
                {
                    // CENTER RING/COLUMN QUADS
                    indices[k + 0] = (short)((i * numSlices + j));
                    indices[k + 1] = (short)(((i + 1) % numSegments) * numSlices + j);
                    indices[k + 2] = (short)((i * numSlices + (j + 1) % numSlices));


                    indices[k + 3] = (short)((i * numSlices + (j + 1) % numSlices));
                    indices[k + 4] = (short)(((i + 1) % numSegments) * numSlices + j);
                    indices[k + 5] = (short)(((i + 1) % numSegments) * numSlices + (j + 1) % numSlices);

                    //indices[k + 3] = (short)(((i + 1) % numSegments * numSlices + j) % numVerts);
                    //indices[k + 4] = (short)((i * numSlices + j + 1) % numVerts);
                    //indices[k + 5] = (short)(((i + 1) % numSegments * numSlices + j + 1) % numVerts);
                    //System.Console.Out.WriteLine(indices[k + 3]);
                    //System.Console.Out.WriteLine(indices[k + 4]);
                    //System.Console.Out.WriteLine(indices[k + 5]);

                    //break;
                    k += 6;
                }
                //break;
            }

            // attributes
            AttributeRange attributeRange = new AttributeRange();
            attributeRange.AttributeId = 0;
            attributeRange.FaceStart = 0;
            attributeRange.FaceCount = numFaces;
            attributeRange.VertexStart = 0;
            attributeRange.VertexCount = vertices.Length;


            mesh = new Mesh(numFaces, vertices.Length, MeshFlags.Managed, CustomVertex.PositionNormalColored.Format, dev);
            mesh.VertexBuffer.SetData(vertices, 0, LockFlags.None);

            mesh.IndexBuffer.SetData(indices, 0, LockFlags.None);
            mesh.SetAttributeTable(new AttributeRange[] { attributeRange });
            mesh.ComputeNormals();
            return mesh;
        }

        public Mesh generateCube()
        {
            Mesh mesh = null;
            
            //verticies
            CustomVertex.PositionNormalColored[] vertices = new CustomVertex.PositionNormalColored[3*8];
            float r = 3.0f;
            float nr = 1.0f/(float)Math.Sqrt(3.0f);
            vertices[0] = new CustomVertex.PositionNormalColored(new Vector3(-r, r, -r), new Vector3(0, 0, -nr), Color.Green.ToArgb()); // lewa, góra, przód
           // vertices[8] = new CustomVertex.PositionNormalColored(new Vector3(-r, r, -r), new Vector3(-nr, nr, -nr), Color.Green.ToArgb());
            //vertices[16] = new CustomVertex.PositionNormalColored(new Vector3(-r, r, -r), new Vector3(-nr, nr, -nr), Color.Green.ToArgb());


            vertices[1] = new CustomVertex.PositionNormalColored(new Vector3(r, r, -r), new Vector3(0, 0, -nr), Color.Green.ToArgb()); // prawa, góra, przód
            //vertices[9] = new CustomVertex.PositionNormalColored(new Vector3(r, r, -r), new Vector3(0, 0, -nr), Color.Green.ToArgb()); // prawa, góra, przód
            //vertices[17] = new CustomVertex.PositionNormalColored(new Vector3(r, r, -r), new Vector3(0, 0, -nr), Color.Green.ToArgb()); // prawa, góra, przód

            vertices[2] = new CustomVertex.PositionNormalColored(new Vector3(-r, -r, -r), new Vector3(0, 0, -nr), Color.Green.ToArgb()); // lewa, dół, przód
            
            vertices[3] = new CustomVertex.PositionNormalColored(new Vector3(r, -r, -r), new Vector3(nr, -nr, -nr), Color.Green.ToArgb()); // prawa, dół, przód
            
            vertices[4] = new CustomVertex.PositionNormalColored(new Vector3(-r, r, r), new Vector3(-nr, nr, nr), Color.Green.ToArgb()); // lewa, góra, tył
            
            vertices[5] = new CustomVertex.PositionNormalColored(new Vector3(r, r, r), new Vector3(nr, nr, nr), Color.Green.ToArgb()); // prawa, góra, tył
            
            vertices[6] = new CustomVertex.PositionNormalColored(new Vector3(-r, -r, r), new Vector3(-nr, -nr, nr), Color.Green.ToArgb());   // lewa, dół, tył       
            
            vertices[7] = new CustomVertex.PositionNormalColored(new Vector3(r,-r, r), new Vector3(nr, -nr, nr), Color.Green.ToArgb()); // prawa, dół, tył

            // indices

            short[] indices =
            {
                0, 1, 2,    // side 1
                2, 1, 3,
                4, 0, 6,    // side 2
                6, 0, 2,
                7, 5, 6,    // side 3
                6, 5, 4,
                3, 1, 7,    // side 4
                7, 1, 5,
                4, 5, 0,    // side 5
                0, 5, 1,
                3, 7, 2,    // side 6
                2, 7, 6,
            };

            // attributes
            AttributeRange attributeRange = new AttributeRange();
            attributeRange.AttributeId = 0;
            attributeRange.FaceStart = 0;
            attributeRange.FaceCount = 12;
            attributeRange.VertexStart = 0;
            attributeRange.VertexCount = vertices.Length;


            mesh = new Mesh(12, vertices.Length, MeshFlags.Managed, CustomVertex.PositionNormalColored.Format, dev);
            mesh.VertexBuffer.SetData(vertices, 0, LockFlags.None);

            mesh.IndexBuffer.SetData(indices, 0, LockFlags.None);
            mesh.SetAttributeTable(new AttributeRange[] { attributeRange });
            mesh.ComputeNormals();
            return mesh;
        }

        public void LoadMesh()
        {
            m = generateCube();
            VertexBuffer vertices = m.VertexBuffer;  
            GraphicsStream stream = vertices.Lock(0, 0, LockFlags.None);
            radius = Geometry.ComputeBoundingSphere(stream, m.NumberVertices, m.VertexFormat, out center);
            Geometry.ComputeBoundingBox(stream, m.NumberVertices, m.VertexFormat, out BoxMin, out BoxMax);
            vertices.Unlock();
        }
    }
}
